package danceDoll;

import com.jme3.animation.Skeleton;
import com.jme3.app.SimpleApplication;
import com.jme3.asset.AssetManager;
import com.jme3.audio.AudioRenderer;
import com.jme3.math.Vector3f;
import com.jme3.niftygui.NiftyJmeDisplay;
import com.jme3.renderer.queue.RenderQueue.Bucket;
import com.jme3.scene.Node;
import com.jme3.scene.Spatial.CullHint;
import com.jme3.shadow.PssmShadowRenderer;
import com.jme3.system.AppSettings;
import de.lessvoid.nifty.Nifty;
import java.io.IOException;
import GuiController.GuiController;
import com.jme3.audio.AudioNode;
import com.jme3.light.PointLight;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Quaternion;

/**
 * Loads the whole Program. Starts with controlling the Model, the Animation, the GUI, Sounds and all Listeners
 * @author Vincent Bosche
 * @version 1.0
 */
public class Initialize extends DanceDoll {

    private DanceDoll danceDoll;
    private Skeleton skelett;
    private NiftyJmeDisplay niftyDisplay;
    private Nifty nifty;
    private AnimationControl ani;
    private AudioNode diskoStuMusic;
    private Record rec;
    private GuiController guiController;
    private PointLight bulb1, bulb2, bulb3, bulb4;   
    public boolean music = true, turntable;
    private boolean isRunning = true, saved;
    private float rotationAngle = 0, rotationSpeed = 2;
    

    public Initialize(DanceDoll dd, AppSettings settings) throws IOException {
        danceDoll = dd;
        SimpleApplication dollApp = (SimpleApplication) danceDoll;

        // Manager speichern
        assetManager = dollApp.getAssetManager();
        audioRenderer = dollApp.getAudioRenderer();
        renderManager = dollApp.getRenderManager();
        stateManager = dollApp.getStateManager();
        listener = dollApp.getListener();
        context = dollApp.getContext();
        mouseInput = context.getMouseInput();
        keyInput = context.getKeyInput();
        inputManager = dollApp.getInputManager();

        // Kamera einstellen        
        cam = dollApp.getCamera();
        cam.lookAt(new Vector3f(0, 0, 0), Vector3f.UNIT_Y);

        viewPort = dollApp.getViewPort();

        // Schatten Renderer
        PssmShadowRenderer pssmRenderer = new PssmShadowRenderer(assetManager, 1024, 1);
        pssmRenderer.setDirection(new Vector3f(-1, -1, -1).normalizeLocal());
        pssmRenderer.setLambda(2.3f);
        pssmRenderer.setShadowIntensity(1.6f);
        pssmRenderer.setFilterMode(PssmShadowRenderer.FilterMode.PCF8);
        pssmRenderer.setEdgesThickness(1);
        //viewPort.addProcessor(pssmRenderer);

        // Turntable & Umgebung laden
        Scenery sc = new Scenery(assetManager);
        Node scenery = sc.getNode();
        rootNode.attachChild(scenery);

        dollApp.getRootNode().attachChild(rootNode);
        dollApp.getRootNode().attachChild(guiNode);

        guiViewPort = dollApp.getGuiViewPort();
        guiViewPort.setClearFlags(false, true, true);

        guiNode.setQueueBucket(Bucket.Gui);
        guiNode.setCullHint(CullHint.Never);
        guiViewPort.attachScene(guiNode);

        // Farbige Pointlights erstellen
        bulb1 = new PointLight();
        bulb1.setColor(ColorRGBA.Yellow);
        bulb1.setRadius(40f);
        bulb1.setPosition(new Vector3f(10f, 10f, 0f));
        bulb2 = new PointLight();
        bulb2.setColor(ColorRGBA.Green);
        bulb2.setRadius(40f);
        bulb2.setPosition(new Vector3f(-10f, 10f, 0f));
        bulb3 = new PointLight();
        bulb3.setColor(ColorRGBA.Blue);
        bulb3.setRadius(40f);
        bulb3.setPosition(new Vector3f(5f, 10f, 0f));
        bulb4 = new PointLight();
        bulb4.setColor(ColorRGBA.Red);
        bulb4.setRadius(40f);
        bulb4.setPosition(new Vector3f(-5.f, 10f, 0f));

        // Model laden
        Model m = sc.getModel();
        skelett = m.getSkeletton();

        // BVH- Einlesen Start-Move
        BVHController bvh = new BVHController("Animations/01_1_Kopf_kratzen.bvh");

        // AnimationControl erstellen
        ani = new AnimationControl(m, this);

        rec = new Record(ani, this);

        if (bvh.chkBVH()) {
            ani.startAnimation(bvh);
        }

        niftyDisplay = new NiftyJmeDisplay(assetManager, inputManager, audioRenderer, guiViewPort);
        nifty = niftyDisplay.getNifty();
        guiController = new GuiController(nifty, dd, this);
        nifty.fromXml("Interface/Gui.xml", "start", guiController);
        guiViewPort.addProcessor(niftyDisplay);
    }

    /**
     * Initialize and start music
     */
    public void initMusic() {
        diskoStuMusic = new AudioNode(assetManager, "Sounds/DiskoStu_Hibtin.wav", false);
        diskoStuMusic.setLooping(true);
        rootNode.attachChild(diskoStuMusic);
        diskoStuMusic.play();
    }

    /**
     * Returns the Skeleton from the Model
     * @return Skeleton
     */
    public Skeleton getSkelet() {
        return this.skelett;
    }

    /**
     * Returns the MainNode, every Models and Animations are loaded to
     * @return MainNode
     */
    public DanceDoll getDoll() {
        return danceDoll;
    }

    /**
     * Returns the NIFTY
     * @return NIFTY
     */
    public Nifty getNifty() {
        return this.nifty;
    }

    @Override
    public AssetManager getAssetManager() {
        return assetManager;
    }

    @Override
    public AudioRenderer getAudioRenderer() {
        return audioRenderer;
    }

    @Override
    public Node getRootNode() {
        return rootNode;
    }

    @Override
    public void simpleUpdate(float tpf) {

        // set Bone Animation
        this.getAnimationControl().animate(tpf);

        // call Record
        if (this.getRecord() != null) {
            this.getRecord().recFrames();
        }

        // rotate Turntable
        rotationAngle += rotationSpeed;

        if (turntable) {
            rootNode.getChild("turntable").setLocalRotation(new Quaternion(new float[]{0, (rotationAngle * FastMath.DEG_TO_RAD), 0}));
        }
        // If music plays, create, add and remove coloured PointLights depending on FrameCount
        // Else remove all coloured PointLights
        if (music) {
            frameCount++;
            if (frameCount % 50 == 0) {
                rootNode.getChild("mainNode").removeLight(bulb2);
                rootNode.getChild("mainNode").addLight(bulb1);
            }
            if (frameCount % 50 == 25) {
                rootNode.getChild("mainNode").removeLight(bulb1);
                rootNode.getChild("mainNode").addLight(bulb2);
            }
            if (frameCount % 25 == 0) {
                rootNode.getChild("mainNode").removeLight(bulb3);
                rootNode.getChild("mainNode").addLight(bulb4);
            }
            if (frameCount % 25 == 12) {
                rootNode.getChild("mainNode").removeLight(bulb4);
                rootNode.getChild("mainNode").addLight(bulb3);
            }
        } else {
            rootNode.getChild("mainNode").removeLight(bulb1);
            rootNode.getChild("mainNode").removeLight(bulb2);
            rootNode.getChild("mainNode").removeLight(bulb3);
            rootNode.getChild("mainNode").removeLight(bulb4);
        }
    }

    /**
     * Returns the Node the GUI is attached
     * @return Node with the GUI
     */
    public Node getGUINode() {
        return guiNode;
    }

    /**
     * Returns the GuiController
     * @return GuiController
     */
    public GuiController getGuiController() {
        return this.guiController;
    }

    /**
     * Gives back the AnimationControl-Class
     * @return the Animation Controller
     */
    public AnimationControl getAnimationControl() {
        return this.ani;
    }

    /**
     * Returns the Record-Class
     * @return the record class
     */
    public Record getRecord() {
        return this.rec;
    }

    /**
     * Get the current angle from the turntable
     * @return current Roation angle
     */
    public float getRotationAngle() {
        return rotationAngle;
    }

    /**
     * Set the rotation Angle from the turntable
     * @param rotationAngle new rotation angle
     */
    public void setRotationAngle(float rotationAngle) {
        this.rotationAngle = rotationAngle;
    }
    
    /**
     * Return if music is paused or not
     * @return Music is paused
     */
    public AudioNode getStuMusic(){
        return diskoStuMusic;
    }
}